package com.tencent.sr.iris.activity.service.event.task;

import com.alibaba.fastjson.JSON;
import com.tencent.sr.iris.activity.common.enums.UserTaskStatusEnum;
import com.tencent.sr.iris.activity.dependency.dto.data.CommissionInfoDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityTaskDTO;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityEventTypeEnum;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.repository.entity.TIrisActivityAwardRecordDO;
import com.tencent.sr.iris.activity.repository.entity.TIrisUserTaskRecordDO;
import com.tencent.sr.iris.activity.service.activity.ActivityCommonService;
import com.tencent.sr.iris.activity.service.activity.IrisUserTaskRecordService;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.config.InviteGiftTempConfig;
import com.tencent.sr.iris.activity.service.event.util.ActivityCommonUtilService;
import com.tencent.sr.iris.activity.service.event.vo.BaseUserTaskDataVO;
import com.tencent.sr.iris.activity.service.event.vo.TaskExecutorExtendInfo;
import com.tencent.sr.iris.activity.service.util.IdCreateorUtil;
import com.tencent.sr.iris.activity.service.util.LocalDateUtil;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Slf4j
@Component
public class IrisInviteCommissionTaskExecutor extends AbstractIrisTaskExecutor {

    @Resource
    private ActivityCommonService activityCommonService;

    @Resource
    private IrisUserTaskRecordService userTaskRecordService;

    @Resource
    private ActivityConfig activityConfig;

    @Resource
    private IdCreateorUtil idCreateorUtil;

    @Resource
    private InviteGiftTempConfig inviteGiftTempConfig;

    @Resource
    private ActivityCommonUtilService activityCommonUtilService;

    /**
     * 重写
     * 邀请有礼活动,以成为见习会员时间做任务时间准入的校验
     *
     * @param eventDTO
     * @param act
     * @param task
     */
    @Override
    void before(ActivityEventDTO eventDTO, ActivityDTO act, ActivityTaskDTO task) {
        //事件类型拦截,20230622前按照老逻辑不需要处理这2中事件
        if (eventDTO.getEventType().equals(ActivityEventTypeEnum.BECOME_TRAINEE.getCode())
                || eventDTO.getEventType().equals(ActivityEventTypeEnum.DISTRIBUTION_ORDER.getCode())) {
            log.info("邀请有礼旧任务不需要处理该类型事件，eventIdempotent:{},eventType:{},taskId:{},taskTime:{}-{}",
                    eventDTO.getIdempotent(), eventDTO.getEventType(), task.getBizId(), task.getStartTime(),
                    task.getEndTime());
            throw new TRetailBizException("邀请有礼旧任务不需要处理该类型事件");
        }
        //TODO 兼容部分3月份的见习会员继续完成4月份的邀请有礼活动,后续过期后可删除此逻辑
        if (eventDTO.getEventTime() <= inviteGiftTempConfig.getExpireTime().getTime()) {
            //白名单有效期范围内
            if (inviteGiftTempConfig.getUidWhiteList().contains(eventDTO.getUid())) {
                //属于白名单的用户,不做邀请有礼的见习会员时间校验
                log.info("邀请有礼4月白名单用户,接着参与4月份的邀请有礼任务");
                return;
            }
        }
        //查询成为见习时间
        Long becomeTraineeTime = activityCommonService.queryTraineeTime(eventDTO.getUid());
        if (becomeTraineeTime < task.getStartTime().getTime() || becomeTraineeTime > task.getEndTime().getTime()) {
            log.info("任务处理：用户成为见习会员时间不在任务时间范围内,不处理，eventIdempotent:{},traineeTime:{},taskId:{},taskTime:{}-{}",
                    eventDTO.getIdempotent(), becomeTraineeTime, task.getBizId(), task.getStartTime(),
                    task.getEndTime());
            throw new TRetailBizException("见习会员时间不在任务时间范围内，不处理");
        }
        if (becomeTraineeTime >= activityCommonService.queryInviteChangeTime(eventDTO.getUid())) {
            log.info("任务处理：用户成为见习会员时间不在旧任务切换时间前,不处理，eventIdempotent:{},traineeTime:{},taskId:{},taskTime:{}-{}",
                    eventDTO.getIdempotent(), becomeTraineeTime, task.getBizId(), task.getStartTime(),
                    task.getEndTime());
            throw new TRetailBizException("见习会员时间不在旧任务切换时间前，不处理");
        }
    }

    @Override
    public void process(ActivityEventDTO msg, ActivityDTO activity, ActivityTaskDTO task,
            List<String> eventHandingInfoList, TaskExecutorExtendInfo taskExecutorExtendInfo) {
        //解析任务执行条件门槛值,区分测试
        addParameterForTask(task, msg);
        log.info("任务门槛值,commissionLimit={},shareTimeLimit={},msgId:{}", task.getCommissionLimit(),
                task.getShareTimeLimit(), msg.getIdempotent());
        //查询任务完成进度
        TIrisUserTaskRecordDO userTaskRecordDO = queryUserTaskRecord(msg.getUid(), activity.getBizId(),
                task.getBizId(), null);
        //已完成的不再更新进度
        if (Objects.nonNull(userTaskRecordDO)) {
            if (UserTaskStatusEnum.FINISHED.getCode() == userTaskRecordDO.getUserTaskStatus()) {
                //已完成任务,不再更新进度
                eventHandingInfoList.add("任务已完成,不再更新进度,userTaskRecordId=" + userTaskRecordDO.getBizId());
                log.info("任务已完成,不再更新进度,userTaskRecordId={},msgId:{}", userTaskRecordDO.getBizId()
                        , msg.getIdempotent());
                return;
            }
            if (UserTaskStatusEnum.UNFINISHED.getCode() == userTaskRecordDO.getUserTaskStatus()) {
                //未完成任务,直接跳过
                log.info("任务未完成,不再更新该任务进度,userTaskRecordId={}", userTaskRecordDO.getBizId());
                eventHandingInfoList.add("任务未完成,不再更新该任务进度,userTaskRecordId=" + userTaskRecordDO.getBizId());
                return;
            }
        } else {
            //查询成为见习时间
            Long becomeTraineeTime = activityCommonService.queryTraineeTime(msg.getUid());
            //新增用户活动任务完成进度
            TIrisUserTaskRecordDO irisUserTaskRecordDO = buildUserTaskRecordDO(
                    activity, task, msg, becomeTraineeTime);
            userTaskRecordDO = irisUserTaskRecordDO;
        }
        //查询佣金
        CommissionInfoDTO commissionInfoDTO = getCommissionInfo(msg.getUid(),
                userTaskRecordDO.getCurrentTaskStartTime(), userTaskRecordDO.getCurrentTaskEndTime());
        //更新进度参数
        userTaskRecordDO.setEstimateCommission(commissionInfoDTO.getEstimateCommission());

        //任务周期结束时间 + 60天以后,计算是否达到门槛：
        //新增判断：T+60以后(不包含T+60天)，【分佣成功】+【订单交易完成且分佣未取消】是否达门槛（T为下单时间）
        int plusDays = activityConfig.getCommissionPlusDays(userTaskRecordDO.getUid());
        LocalDate taskEndDatePlus60 = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate().plusDays(plusDays);

        Integer commission = Objects.isNull(commissionInfoDTO.getCommission()) ? 0 : commissionInfoDTO.getCommission();
        LocalDate currentLocalDate = LocalDate.now();
        if (currentLocalDate.isAfter(taskEndDatePlus60)) {
            Integer waitCommissionAmt = Objects.isNull(commissionInfoDTO.getWaitCommissionAmt()) ? 0
                    : commissionInfoDTO.getWaitCommissionAmt();
            commission = commission + waitCommissionAmt;
        }
        userTaskRecordDO.setCommission(commission);
        userTaskRecordDO.setGmv(commissionInfoDTO.getGmv());

        userTaskRecordDO.setShareCount(commissionInfoDTO.getShareUvTo29());

        String extInfo = activityCommonUtilService.buildTaskRecordExtInfo(userTaskRecordDO.getExtInfo(), commissionInfoDTO);
        userTaskRecordDO.setExtInfo(extInfo);

        //填充任务完成状态
        fillTaskRecordStatus(msg, activity, task, userTaskRecordDO, LocalDate.now());

        //任务进度更新
        TIrisActivityAwardRecordDO awardRecordDO = null;
        if (BooleanUtils.isTrue(UserTaskStatusEnum.FINISHED.getCode() == userTaskRecordDO.getUserTaskStatus())) {
            eventHandingInfoList.add("邀请有礼任务达成");
            log.info("邀请有礼任务达成,uid:{},commissionInfoDTO:{},msg:{}", msg.getUid(),
                    JSON.toJSONString(commissionInfoDTO), JSON.toJSONString(msg));
            //发放权益
            awardRecordDO = activityCommonService.sendAwardForSupervisor(userTaskRecordDO, task);
        } else {
            eventHandingInfoList.add("邀请有礼任务未达成");
        }

        //更新用户活动任务完成进度
        userTaskRecordService.updateUserTaskRecordStatus(userTaskRecordDO, awardRecordDO);
    }

    @Override
    public void fillTaskRecordStatus(ActivityEventDTO eventDTO, ActivityDTO act, ActivityTaskDTO task,
            TIrisUserTaskRecordDO userTaskRecordDO, LocalDate currentLocalDate) {
        LocalDate currentTaskStartDate = userTaskRecordDO.getCurrentTaskStartTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        LocalDate currentTaskEndDate = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        int plusDays = activityConfig.getCommissionPlusDays(userTaskRecordDO.getUid());
        LocalDate currentTaskEndDatePlus60 = userTaskRecordDO.getCurrentTaskEndTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate().plusDays(plusDays);

        Integer estimateCommission = userTaskRecordDO.getEstimateCommission();
        Integer commission = userTaskRecordDO.getCommission();
        Integer shareCount = userTaskRecordDO.getShareCount();

        //在任务周期内
        if (LocalDateUtil.isLocalDateBetween(currentLocalDate, currentTaskStartDate, currentTaskEndDate)) {
            //设置预估佣金任务完成状态
            if (estimateCommission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //实际佣金及分享次数条件判断
            if (commission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                //任务已完成
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //在任务周期结束后60天内
        } else if (currentLocalDate.isAfter(currentTaskEndDate)
                && (currentLocalDate.equals(currentTaskEndDatePlus60) || currentLocalDate
                .isBefore(currentTaskEndDatePlus60))) {
            //有效分享次数没达成，直接判断为未完成
            if (shareCount < task.getShareTimeLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                return;
            }

            LocalDate endDatePlusOne = currentTaskEndDate.plusDays(1);
            if (estimateCommission >= task.getCommissionLimit()) {
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else if (currentLocalDate.isAfter(endDatePlusOne)) {
                //预估佣金没达成，且已过任务结束时间24小时，直接判断为未完成
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                return;
            }

            //实际佣金条件判断
            if (commission >= task.getCommissionLimit()) {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
            }
            //任务周期结束60天后
        } else if (currentLocalDate.isAfter(currentTaskEndDatePlus60)) {
            //实际佣金及分享次数条件判断
            if (commission >= task.getCommissionLimit()
                    && shareCount >= task.getShareTimeLimit()) {
                //任务已完成
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.FINISHED.getCode());
            } else {
                userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
                userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.UNFINISHED.getCode());
            }
        }
    }

    private Date getTaskEndTime(ActivityTaskDTO taskDTO, Long becomeTraineeTime) {
        Date traineeTimeTo29 = TraineeTimeTo29(becomeTraineeTime);
        LocalDateTime taskEndTime = taskDTO.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        //见习会员+29天
        LocalDateTime traineeDateTo29 = traineeTimeTo29.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        //任务进度结束时间为 min(见习会员+29天时间,任务结束时间)
        LocalDateTime currentTaskEndTime = taskEndTime.isBefore(traineeDateTo29) ? taskEndTime : traineeDateTo29;
        return Date.from(currentTaskEndTime.atZone(ZoneId.systemDefault()).toInstant());
    }


    @Override
    public boolean executeAward(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task) {
        return false;
    }

    @Override
    public boolean checkTaskThreshold(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task,
            BaseUserTaskDataVO userTaskDataVO) {
        return false;
    }

    @Override
    public BaseUserTaskDataVO prepareUserTaskData(ActivityEventDTO event, ActivityDTO act, ActivityTaskDTO task) {
        return null;
    }

    private Pair<Boolean/*任务完成状态*/, Boolean/*预估佣金完成状态*/> checkTaskFinish(ActivityTaskDTO task
            , CommissionInfoDTO commissionInfoDTO) {
        boolean taskStatus = false;
        boolean taskEstimateStatus = false;
        if (commissionInfoDTO.getCommission() >= task.getCommissionLimit()
                && commissionInfoDTO.getShareUvTo29() >= task.getShareTimeLimit()) {
            taskStatus = true;
        }
        if (commissionInfoDTO.getEstimateCommission() >= task.getCommissionLimit()
                && commissionInfoDTO.getShareUvTo29() >= task.getShareTimeLimit()) {
            taskEstimateStatus = true;
        }
        return Pair.of(taskStatus, taskEstimateStatus);
    }

    private void addParameterForTask(ActivityTaskDTO task, ActivityEventDTO msg) {
        task.parseLimitCondition();
    }

    public CommissionInfoDTO getCommissionInfo(String uid, Date becomeTraineeTime, Date taskEndTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String startTime = sdf.format(becomeTraineeTime);
        String endTime = sdf.format(taskEndTime);

        return activityCommonService.queryCommissionInfo(uid, startTime, endTime);
    }

    private TIrisUserTaskRecordDO buildUserTaskRecordDO(ActivityDTO activity, ActivityTaskDTO taskDTO,
            ActivityEventDTO msg, Long becomeTraineeTime) {
        TIrisUserTaskRecordDO userTaskRecordDO = new TIrisUserTaskRecordDO();
        userTaskRecordDO.setBizId(idCreateorUtil.genId());
        userTaskRecordDO.setUid(msg.getUid());
        userTaskRecordDO.setPid(msg.getPid());
        userTaskRecordDO.setActivityId(activity.getBizId());
        userTaskRecordDO.setTaskId(taskDTO.getBizId());
        userTaskRecordDO.setActivityType(activity.getActivityType());
        userTaskRecordDO.setPeriodType(activity.getPeriodType());
        userTaskRecordDO.setUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
        userTaskRecordDO.setEstimateUserTaskStatus(UserTaskStatusEnum.PROGRESS.getCode());
        //任务结束时间
        //Date taskEndTime = getTaskEndTime(taskDTO, becomeTraineeTime);
        userTaskRecordDO.setCurrentTaskStartTime(initCurrentTaskStartTime(becomeTraineeTime));
        userTaskRecordDO.setCurrentTaskEndTime(initCurrentTaskEndTime(becomeTraineeTime));
        userTaskRecordDO.setTier(taskDTO.getTier());
        userTaskRecordService.saveUserTaskRecord(userTaskRecordDO);
        return userTaskRecordDO;
    }

    public Date initCurrentTaskStartTime(Long becomeTraineeTime) {
        return new Date(becomeTraineeTime);
    }

    public Date initCurrentTaskEndTime(Long becomeTraineeTime) {
        return TraineeTimeTo29(becomeTraineeTime);
    }
}
